using Fantasy.SourceGenerator.Common;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Fantasy.SourceGenerator.Generators
{
    [Generator]
    public partial class EntityTypeCollectionGenerate : IIncrementalGenerator
    {
        public void Initialize(IncrementalGeneratorInitializationContext context)
        {
            // 查找所有实现了 EventSystem 相关抽象类的类
            var protoBufTypes = context.SyntaxProvider
                .CreateSyntaxProvider(
                    predicate: static (node, _) => IsEntityClass(node),
                    transform: static (ctx, _) => GetEntityTypeInfo(ctx))
                .Where(static info => info != null)
                .Collect();
            // 组合编译信息和找到的类型
            var compilationAndTypes = context.CompilationProvider.Combine(protoBufTypes);
            // 注册源代码输出
            context.RegisterSourceOutput(compilationAndTypes, static (spc, source) =>
            {
                // 检查1: 是否定义了 FANTASY_NET 或 FANTASY_UNITY 预编译符号
                if (!CompilationHelper.HasFantasyDefine(source.Left))
                {
                    return;
                }

                // 检查2: 是否引用了 Fantasy 框架的核心类型
                if (source.Left.GetTypeByMetadataName("Fantasy.Assembly.IEntityTypeCollectionRegistrar") == null)
                {
                    return;
                }

                GenerateRegistrationCode(spc, source.Left, source.Right!);
            });
        }
        
        /// <summary>
        /// 生成注册代码
        /// </summary>
        private static void GenerateRegistrationCode(
            SourceProductionContext context,
            Compilation compilation,
            IEnumerable<EntityTypeInfo> entityTypeInfos)
        {
            var entityTypeList = entityTypeInfos.ToList();
            // 获取当前程序集名称（仅用于注释）
            var assemblyName = compilation.AssemblyName ?? "Unknown";
            var builder = new SourceCodeBuilder();
            // 添加文件头
            builder.AppendLine(GeneratorConstants.AutoGeneratedHeader);
            // 添加 using
            builder.AddUsings(
                "System",
                "System.Collections.Generic",
                "Fantasy.Assembly",
                "Fantasy.DataStructure.Collection",
                "Fantasy.Event"
            );
            builder.AppendLine();
            // 开始命名空间（固定使用 Fantasy.Generated）
            builder.BeginNamespace("Fantasy.Generated");
            // 开始类定义（实现 IEntityTypeCollectionRegistrar 接口）
            builder.AddXmlComment($"Automatically generated Entity Type collection class for {assemblyName}");
            builder.BeginClass("EntityTypeCollectionRegistrar", "internal sealed", "IEntityTypeCollectionRegistrar");
            // 生成 GetEntityTypes 方法
            GetEntityTypesMethod(builder, entityTypeList);
            builder.AppendLine();
            // 结束类和命名空间
            builder.EndClass();
            builder.EndNamespace();
            // 输出源代码
            context.AddSource("EntityTypeCollectionRegistrar.g.cs", builder.ToString());
        }
        
        private static void GetEntityTypesMethod(SourceCodeBuilder builder, List<EntityTypeInfo> entityTypeInfos)
        {
            builder.AddXmlComment("All Entity Types");
            builder.BeginMethod("public List<Type> GetEntityTypes()");
            
            if (entityTypeInfos.Any())
            {
                builder.AppendLine($"return new List<Type>({entityTypeInfos.Count})");
                builder.AppendLine("{");
                builder.Indent();
                foreach (var system in entityTypeInfos)
                {
                    builder.AppendLine($"typeof({system.EntityTypeFullName}),");
                }
                builder.Unindent();
                builder.AppendLine("};");
                builder.AppendLine();
            }
            else
            {
                builder.AppendLine($"return new List<Type>();");
            }
            
            builder.EndMethod();
        }
        
        private static bool IsEntityClass(SyntaxNode node)
        {
            if (node is not ClassDeclarationSyntax classDecl)
            {
                return false;
            }
            // 必须有基类型列表（实现接口）
            return classDecl.BaseList != null && classDecl.BaseList.Types.Any();
        }
        
        private static EntityTypeInfo? GetEntityTypeInfo(GeneratorSyntaxContext context)
        {
            var classDecl = (ClassDeclarationSyntax)context.Node;
            var semanticModel = context.SemanticModel;
            
            // 检查是否继承自 Entity 或 Entity<T>
            if (!InheritsFromEntity(classDecl, semanticModel))
            {
                return null;
            }
            
            var symbol = context.SemanticModel.GetDeclaredSymbol(classDecl) as INamedTypeSymbol;

            if (symbol == null || !symbol.IsInstantiable())
            {
                return null;
            }
            
            return new EntityTypeInfo(
                symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
                symbol.Name
            );
        }
        
        private static bool InheritsFromEntity(ClassDeclarationSyntax classDecl, SemanticModel semanticModel)
        {
            if (classDecl.BaseList == null)
            {
                return false;
            }

            foreach (var baseType in classDecl.BaseList.Types)
            {
                var typeInfo = semanticModel.GetTypeInfo(baseType.Type);
                var baseTypeSymbol = typeInfo.Type as INamedTypeSymbol;

                if (baseTypeSymbol == null)
                {
                    continue;
                }

                // 检查是否是 Entity（非泛型）
                if (baseTypeSymbol.Name == "Entity" && baseTypeSymbol.Arity == 0)
                {
                    return true;
                }

                // 检查是否是 Entity<T>（泛型）
                if (baseTypeSymbol.IsGenericType)
                {
                    var originalDef = baseTypeSymbol.OriginalDefinition;
                    if (originalDef.Name == "Entity" && originalDef.Arity == 1)
                    {
                        return true;
                    }
                }
            }

            return false;
        }
        
        private sealed record EntityTypeInfo(
            string EntityTypeFullName,
            string EntityTypeName
        );
    }
}